1   /*
2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  /**********************************************************************
27   **********************************************************************
28   **********************************************************************
29   *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
30   *** As  an unpublished  work pursuant to Title 17 of the United    ***
31   *** States Code.  All rights reserved.                             ***
32   **********************************************************************
33   **********************************************************************
34   **********************************************************************/
35  
36  package java.awt.color;
37  
38  import sun.java2d.cmm.PCMM;
39  import sun.java2d.cmm.CMSManager;
40  import sun.java2d.cmm.ProfileDeferralMgr;
41  import sun.java2d.cmm.ProfileDeferralInfo;
42  import sun.java2d.cmm.ProfileActivator;
43  
44  import java.io.File;
45  import java.io.FileInputStream;
46  import java.io.FileNotFoundException;
47  import java.io.FileOutputStream;
48  import java.io.IOException;
49  import java.io.InputStream;
50  import java.io.ObjectInputStream;
51  import java.io.ObjectOutputStream;
52  import java.io.ObjectStreamException;
53  import java.io.OutputStream;
54  import java.io.Serializable;
55  
56  import java.util.StringTokenizer;
57  
58  import java.security.AccessController;
59  import java.security.PrivilegedAction;
60  
61  
62  /**
63   * A representation of color profile data for device independent and
64   * device dependent color spaces based on the International Color
65   * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
66   * (see <A href="http://www.color.org"> http://www.color.org</A>).
67   * <p>
68   * An ICC_ColorSpace object can be constructed from an appropriate
69   * ICC_Profile.
70   * Typically, an ICC_ColorSpace would be associated with an ICC
71   * Profile which is either an input, display, or output profile (see
72   * the ICC specification).  There are also device link, abstract,
73   * color space conversion, and named color profiles.  These are less
74   * useful for tagging a color or image, but are useful for other
75   * purposes (in particular device link profiles can provide improved
76   * performance for converting from one device's color space to
77   * another's).
78   * <p>
79   * ICC Profiles represent transformations from the color space of
80   * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
81   * Profiles of interest for tagging images or colors have a PCS
82   * which is one of the two specific device independent
83   * spaces (one CIEXYZ space and one CIELab space) defined in the
84   * ICC Profile Format Specification.  Most profiles of interest
85   * either have invertible transformations or explicitly specify
86   * transformations going both directions.
87   * <p>
88   * @see ICC_ColorSpace
89   */
90  
91  
92  public class ICC_Profile implements Serializable {
93  
94      private static final long serialVersionUID = -3938515861990936766L;
95  
96      transient long ID;
97  
98      private transient ProfileDeferralInfo deferralInfo;
99      private transient ProfileActivator profileActivator;
100 
101     // Registry of singleton profile objects for specific color spaces
102     // defined in the ColorSpace class (e.g. CS_sRGB), see
103     // getInstance(int cspace) factory method.
104     private static ICC_Profile sRGBprofile;
105     private static ICC_Profile XYZprofile;
106     private static ICC_Profile PYCCprofile;
107     private static ICC_Profile GRAYprofile;
108     private static ICC_Profile LINEAR_RGBprofile;
109 
110 
111     /**
112      * Profile class is input.
113      */
114     public static final int CLASS_INPUT = 0;
115 
116     /**
117      * Profile class is display.
118      */
119     public static final int CLASS_DISPLAY = 1;
120 
121     /**
122      * Profile class is output.
123      */
124     public static final int CLASS_OUTPUT = 2;
125 
126     /**
127      * Profile class is device link.
128      */
129     public static final int CLASS_DEVICELINK = 3;
130 
131     /**
132      * Profile class is color space conversion.
133      */
134     public static final int CLASS_COLORSPACECONVERSION = 4;
135 
136     /**
137      * Profile class is abstract.
138      */
139     public static final int CLASS_ABSTRACT = 5;
140 
141     /**
142      * Profile class is named color.
143      */
144     public static final int CLASS_NAMEDCOLOR = 6;
145 
146 
147     /**
148      * ICC Profile Color Space Type Signature: 'XYZ '.
149      */
150     public static final int icSigXYZData        = 0x58595A20;    /* 'XYZ ' */
151 
152     /**
153      * ICC Profile Color Space Type Signature: 'Lab '.
154      */
155     public static final int icSigLabData        = 0x4C616220;    /* 'Lab ' */
156 
157     /**
158      * ICC Profile Color Space Type Signature: 'Luv '.
159      */
160     public static final int icSigLuvData        = 0x4C757620;    /* 'Luv ' */
161 
162     /**
163      * ICC Profile Color Space Type Signature: 'YCbr'.
164      */
165     public static final int icSigYCbCrData        = 0x59436272;    /* 'YCbr' */
166 
167     /**
168      * ICC Profile Color Space Type Signature: 'Yxy '.
169      */
170     public static final int icSigYxyData        = 0x59787920;    /* 'Yxy ' */
171 
172     /**
173      * ICC Profile Color Space Type Signature: 'RGB '.
174      */
175     public static final int icSigRgbData        = 0x52474220;    /* 'RGB ' */
176 
177     /**
178      * ICC Profile Color Space Type Signature: 'GRAY'.
179      */
180     public static final int icSigGrayData        = 0x47524159;    /* 'GRAY' */
181 
182     /**
183      * ICC Profile Color Space Type Signature: 'HSV'.
184      */
185     public static final int icSigHsvData        = 0x48535620;    /* 'HSV ' */
186 
187     /**
188      * ICC Profile Color Space Type Signature: 'HLS'.
189      */
190     public static final int icSigHlsData        = 0x484C5320;    /* 'HLS ' */
191 
192     /**
193      * ICC Profile Color Space Type Signature: 'CMYK'.
194      */
195     public static final int icSigCmykData        = 0x434D594B;    /* 'CMYK' */
196 
197     /**
198      * ICC Profile Color Space Type Signature: 'CMY '.
199      */
200     public static final int icSigCmyData        = 0x434D5920;    /* 'CMY ' */
201 
202     /**
203      * ICC Profile Color Space Type Signature: '2CLR'.
204      */
205     public static final int icSigSpace2CLR        = 0x32434C52;    /* '2CLR' */
206 
207     /**
208      * ICC Profile Color Space Type Signature: '3CLR'.
209      */
210     public static final int icSigSpace3CLR        = 0x33434C52;    /* '3CLR' */
211 
212     /**
213      * ICC Profile Color Space Type Signature: '4CLR'.
214      */
215     public static final int icSigSpace4CLR        = 0x34434C52;    /* '4CLR' */
216 
217     /**
218      * ICC Profile Color Space Type Signature: '5CLR'.
219      */
220     public static final int icSigSpace5CLR        = 0x35434C52;    /* '5CLR' */
221 
222     /**
223      * ICC Profile Color Space Type Signature: '6CLR'.
224      */
225     public static final int icSigSpace6CLR        = 0x36434C52;    /* '6CLR' */
226 
227     /**
228      * ICC Profile Color Space Type Signature: '7CLR'.
229      */
230     public static final int icSigSpace7CLR        = 0x37434C52;    /* '7CLR' */
231 
232     /**
233      * ICC Profile Color Space Type Signature: '8CLR'.
234      */
235     public static final int icSigSpace8CLR        = 0x38434C52;    /* '8CLR' */
236 
237     /**
238      * ICC Profile Color Space Type Signature: '9CLR'.
239      */
240     public static final int icSigSpace9CLR        = 0x39434C52;    /* '9CLR' */
241 
242     /**
243      * ICC Profile Color Space Type Signature: 'ACLR'.
244      */
245     public static final int icSigSpaceACLR        = 0x41434C52;    /* 'ACLR' */
246 
247     /**
248      * ICC Profile Color Space Type Signature: 'BCLR'.
249      */
250     public static final int icSigSpaceBCLR        = 0x42434C52;    /* 'BCLR' */
251 
252     /**
253      * ICC Profile Color Space Type Signature: 'CCLR'.
254      */
255     public static final int icSigSpaceCCLR        = 0x43434C52;    /* 'CCLR' */
256 
257     /**
258      * ICC Profile Color Space Type Signature: 'DCLR'.
259      */
260     public static final int icSigSpaceDCLR        = 0x44434C52;    /* 'DCLR' */
261 
262     /**
263      * ICC Profile Color Space Type Signature: 'ECLR'.
264      */
265     public static final int icSigSpaceECLR        = 0x45434C52;    /* 'ECLR' */
266 
267     /**
268      * ICC Profile Color Space Type Signature: 'FCLR'.
269      */
270     public static final int icSigSpaceFCLR        = 0x46434C52;    /* 'FCLR' */
271 
272 
273     /**
274      * ICC Profile Class Signature: 'scnr'.
275      */
276     public static final int icSigInputClass       = 0x73636E72;    /* 'scnr' */
277 
278     /**
279      * ICC Profile Class Signature: 'mntr'.
280      */
281     public static final int icSigDisplayClass     = 0x6D6E7472;    /* 'mntr' */
282 
283     /**
284      * ICC Profile Class Signature: 'prtr'.
285      */
286     public static final int icSigOutputClass      = 0x70727472;    /* 'prtr' */
287 
288     /**
289      * ICC Profile Class Signature: 'link'.
290      */
291     public static final int icSigLinkClass        = 0x6C696E6B;    /* 'link' */
292 
293     /**
294      * ICC Profile Class Signature: 'abst'.
295      */
296     public static final int icSigAbstractClass    = 0x61627374;    /* 'abst' */
297 
298     /**
299      * ICC Profile Class Signature: 'spac'.
300      */
301     public static final int icSigColorSpaceClass  = 0x73706163;    /* 'spac' */
302 
303     /**
304      * ICC Profile Class Signature: 'nmcl'.
305      */
306     public static final int icSigNamedColorClass  = 0x6e6d636c;    /* 'nmcl' */
307 
308 
309     /**
310      * ICC Profile Rendering Intent: Perceptual.
311      */
312     public static final int icPerceptual            = 0;
313 
314     /**
315      * ICC Profile Rendering Intent: RelativeColorimetric.
316      */
317     public static final int icRelativeColorimetric    = 1;
318 
319     /**
320      * ICC Profile Rendering Intent: Media-RelativeColorimetric.
321      * @since 1.5
322      */
323     public static final int icMediaRelativeColorimetric = 1;
324 
325     /**
326      * ICC Profile Rendering Intent: Saturation.
327      */
328     public static final int icSaturation            = 2;
329 
330     /**
331      * ICC Profile Rendering Intent: AbsoluteColorimetric.
332      */
333     public static final int icAbsoluteColorimetric    = 3;
334 
335     /**
336      * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
337      * @since 1.5
338      */
339     public static final int icICCAbsoluteColorimetric = 3;
340 
341 
342     /**
343      * ICC Profile Tag Signature: 'head' - special.
344      */
345     public static final int icSigHead      = 0x68656164; /* 'head' - special */
346 
347     /**
348      * ICC Profile Tag Signature: 'A2B0'.
349      */
350     public static final int icSigAToB0Tag         = 0x41324230;    /* 'A2B0' */
351 
352     /**
353      * ICC Profile Tag Signature: 'A2B1'.
354      */
355     public static final int icSigAToB1Tag         = 0x41324231;    /* 'A2B1' */
356 
357     /**
358      * ICC Profile Tag Signature: 'A2B2'.
359      */
360     public static final int icSigAToB2Tag         = 0x41324232;    /* 'A2B2' */
361 
362     /**
363      * ICC Profile Tag Signature: 'bXYZ'.
364      */
365     public static final int icSigBlueColorantTag  = 0x6258595A;    /* 'bXYZ' */
366 
367     /**
368      * ICC Profile Tag Signature: 'bXYZ'.
369      * @since 1.5
370      */
371     public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
372 
373     /**
374      * ICC Profile Tag Signature: 'bTRC'.
375      */
376     public static final int icSigBlueTRCTag       = 0x62545243;    /* 'bTRC' */
377 
378     /**
379      * ICC Profile Tag Signature: 'B2A0'.
380      */
381     public static final int icSigBToA0Tag         = 0x42324130;    /* 'B2A0' */
382 
383     /**
384      * ICC Profile Tag Signature: 'B2A1'.
385      */
386     public static final int icSigBToA1Tag         = 0x42324131;    /* 'B2A1' */
387 
388     /**
389      * ICC Profile Tag Signature: 'B2A2'.
390      */
391     public static final int icSigBToA2Tag         = 0x42324132;    /* 'B2A2' */
392 
393     /**
394      * ICC Profile Tag Signature: 'calt'.
395      */
396     public static final int icSigCalibrationDateTimeTag = 0x63616C74;
397                                                                    /* 'calt' */
398 
399     /**
400      * ICC Profile Tag Signature: 'targ'.
401      */
402     public static final int icSigCharTargetTag    = 0x74617267;    /* 'targ' */
403 
404     /**
405      * ICC Profile Tag Signature: 'cprt'.
406      */
407     public static final int icSigCopyrightTag     = 0x63707274;    /* 'cprt' */
408 
409     /**
410      * ICC Profile Tag Signature: 'crdi'.
411      */
412     public static final int icSigCrdInfoTag       = 0x63726469;    /* 'crdi' */
413 
414     /**
415      * ICC Profile Tag Signature: 'dmnd'.
416      */
417     public static final int icSigDeviceMfgDescTag = 0x646D6E64;    /* 'dmnd' */
418 
419     /**
420      * ICC Profile Tag Signature: 'dmdd'.
421      */
422     public static final int icSigDeviceModelDescTag = 0x646D6464;  /* 'dmdd' */
423 
424     /**
425      * ICC Profile Tag Signature: 'devs'.
426      */
427     public static final int icSigDeviceSettingsTag =  0x64657673;  /* 'devs' */
428 
429     /**
430      * ICC Profile Tag Signature: 'gamt'.
431      */
432     public static final int icSigGamutTag         = 0x67616D74;    /* 'gamt' */
433 
434     /**
435      * ICC Profile Tag Signature: 'kTRC'.
436      */
437     public static final int icSigGrayTRCTag       = 0x6b545243;    /* 'kTRC' */
438 
439     /**
440      * ICC Profile Tag Signature: 'gXYZ'.
441      */
442     public static final int icSigGreenColorantTag = 0x6758595A;    /* 'gXYZ' */
443 
444     /**
445      * ICC Profile Tag Signature: 'gXYZ'.
446      * @since 1.5
447      */
448     public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
449 
450     /**
451      * ICC Profile Tag Signature: 'gTRC'.
452      */
453     public static final int icSigGreenTRCTag      = 0x67545243;    /* 'gTRC' */
454 
455     /**
456      * ICC Profile Tag Signature: 'lumi'.
457      */
458     public static final int icSigLuminanceTag     = 0x6C756d69;    /* 'lumi' */
459 
460     /**
461      * ICC Profile Tag Signature: 'meas'.
462      */
463     public static final int icSigMeasurementTag   = 0x6D656173;    /* 'meas' */
464 
465     /**
466      * ICC Profile Tag Signature: 'bkpt'.
467      */
468     public static final int icSigMediaBlackPointTag = 0x626B7074;  /* 'bkpt' */
469 
470     /**
471      * ICC Profile Tag Signature: 'wtpt'.
472      */
473     public static final int icSigMediaWhitePointTag = 0x77747074;  /* 'wtpt' */
474 
475     /**
476      * ICC Profile Tag Signature: 'ncl2'.
477      */
478     public static final int icSigNamedColor2Tag   = 0x6E636C32;    /* 'ncl2' */
479 
480     /**
481      * ICC Profile Tag Signature: 'resp'.
482      */
483     public static final int icSigOutputResponseTag = 0x72657370;   /* 'resp' */
484 
485     /**
486      * ICC Profile Tag Signature: 'pre0'.
487      */
488     public static final int icSigPreview0Tag      = 0x70726530;    /* 'pre0' */
489 
490     /**
491      * ICC Profile Tag Signature: 'pre1'.
492      */
493     public static final int icSigPreview1Tag      = 0x70726531;    /* 'pre1' */
494 
495     /**
496      * ICC Profile Tag Signature: 'pre2'.
497      */
498     public static final int icSigPreview2Tag      = 0x70726532;    /* 'pre2' */
499 
500     /**
501      * ICC Profile Tag Signature: 'desc'.
502      */
503     public static final int icSigProfileDescriptionTag = 0x64657363;
504                                                                    /* 'desc' */
505 
506     /**
507      * ICC Profile Tag Signature: 'pseq'.
508      */
509     public static final int icSigProfileSequenceDescTag = 0x70736571;
510                                                                    /* 'pseq' */
511 
512     /**
513      * ICC Profile Tag Signature: 'psd0'.
514      */
515     public static final int icSigPs2CRD0Tag       = 0x70736430;    /* 'psd0' */
516 
517     /**
518      * ICC Profile Tag Signature: 'psd1'.
519      */
520     public static final int icSigPs2CRD1Tag       = 0x70736431;    /* 'psd1' */
521 
522     /**
523      * ICC Profile Tag Signature: 'psd2'.
524      */
525     public static final int icSigPs2CRD2Tag       = 0x70736432;    /* 'psd2' */
526 
527     /**
528      * ICC Profile Tag Signature: 'psd3'.
529      */
530     public static final int icSigPs2CRD3Tag       = 0x70736433;    /* 'psd3' */
531 
532     /**
533      * ICC Profile Tag Signature: 'ps2s'.
534      */
535     public static final int icSigPs2CSATag        = 0x70733273;    /* 'ps2s' */
536 
537     /**
538      * ICC Profile Tag Signature: 'ps2i'.
539      */
540     public static final int icSigPs2RenderingIntentTag = 0x70733269;
541                                                                    /* 'ps2i' */
542 
543     /**
544      * ICC Profile Tag Signature: 'rXYZ'.
545      */
546     public static final int icSigRedColorantTag   = 0x7258595A;    /* 'rXYZ' */
547 
548     /**
549      * ICC Profile Tag Signature: 'rXYZ'.
550      * @since 1.5
551      */
552     public static final int icSigRedMatrixColumnTag = 0x7258595A;  /* 'rXYZ' */
553 
554     /**
555      * ICC Profile Tag Signature: 'rTRC'.
556      */
557     public static final int icSigRedTRCTag        = 0x72545243;    /* 'rTRC' */
558 
559     /**
560      * ICC Profile Tag Signature: 'scrd'.
561      */
562     public static final int icSigScreeningDescTag = 0x73637264;    /* 'scrd' */
563 
564     /**
565      * ICC Profile Tag Signature: 'scrn'.
566      */
567     public static final int icSigScreeningTag     = 0x7363726E;    /* 'scrn' */
568 
569     /**
570      * ICC Profile Tag Signature: 'tech'.
571      */
572     public static final int icSigTechnologyTag    = 0x74656368;    /* 'tech' */
573 
574     /**
575      * ICC Profile Tag Signature: 'bfd '.
576      */
577     public static final int icSigUcrBgTag         = 0x62666420;    /* 'bfd ' */
578 
579     /**
580      * ICC Profile Tag Signature: 'vued'.
581      */
582     public static final int icSigViewingCondDescTag = 0x76756564;  /* 'vued' */
583 
584     /**
585      * ICC Profile Tag Signature: 'view'.
586      */
587     public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
588 
589     /**
590      * ICC Profile Tag Signature: 'chrm'.
591      */
592     public static final int icSigChromaticityTag  = 0x6368726d;    /* 'chrm' */
593 
594     /**
595      * ICC Profile Tag Signature: 'chad'.
596      * @since 1.5
597      */
598     public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
599 
600     /**
601      * ICC Profile Tag Signature: 'clro'.
602      * @since 1.5
603      */
604     public static final int icSigColorantOrderTag = 0x636C726F;    /* 'clro' */
605 
606     /**
607      * ICC Profile Tag Signature: 'clrt'.
608      * @since 1.5
609      */
610     public static final int icSigColorantTableTag = 0x636C7274;    /* 'clrt' */
611 
612 
613     /**
614      * ICC Profile Header Location: profile size in bytes.
615      */
616     public static final int icHdrSize         = 0;  /* Profile size in bytes */
617 
618     /**
619      * ICC Profile Header Location: CMM for this profile.
620      */
621     public static final int icHdrCmmId        = 4;  /* CMM for this profile */
622 
623     /**
624      * ICC Profile Header Location: format version number.
625      */
626     public static final int icHdrVersion      = 8;  /* Format version number */
627 
628     /**
629      * ICC Profile Header Location: type of profile.
630      */
631     public static final int icHdrDeviceClass  = 12; /* Type of profile */
632 
633     /**
634      * ICC Profile Header Location: color space of data.
635      */
636     public static final int icHdrColorSpace   = 16; /* Color space of data */
637 
638     /**
639      * ICC Profile Header Location: PCS - XYZ or Lab only.
640      */
641     public static final int icHdrPcs          = 20; /* PCS - XYZ or Lab only */
642 
643     /**
644      * ICC Profile Header Location: date profile was created.
645      */
646     public static final int icHdrDate       = 24; /* Date profile was created */
647 
648     /**
649      * ICC Profile Header Location: icMagicNumber.
650      */
651     public static final int icHdrMagic        = 36; /* icMagicNumber */
652 
653     /**
654      * ICC Profile Header Location: primary platform.
655      */
656     public static final int icHdrPlatform     = 40; /* Primary Platform */
657 
658     /**
659      * ICC Profile Header Location: various bit settings.
660      */
661     public static final int icHdrFlags        = 44; /* Various bit settings */
662 
663     /**
664      * ICC Profile Header Location: device manufacturer.
665      */
666     public static final int icHdrManufacturer = 48; /* Device manufacturer */
667 
668     /**
669      * ICC Profile Header Location: device model number.
670      */
671     public static final int icHdrModel        = 52; /* Device model number */
672 
673     /**
674      * ICC Profile Header Location: device attributes.
675      */
676     public static final int icHdrAttributes   = 56; /* Device attributes */
677 
678     /**
679      * ICC Profile Header Location: rendering intent.
680      */
681     public static final int icHdrRenderingIntent = 64; /* Rendering intent */
682 
683     /**
684      * ICC Profile Header Location: profile illuminant.
685      */
686     public static final int icHdrIlluminant   = 68; /* Profile illuminant */
687 
688     /**
689      * ICC Profile Header Location: profile creator.
690      */
691     public static final int icHdrCreator      = 80; /* Profile creator */
692 
693     /**
694      * ICC Profile Header Location: profile's ID.
695      * @since 1.5
696      */
697     public static final int icHdrProfileID = 84; /* Profile's ID */
698 
699 
700     /**
701      * ICC Profile Constant: tag type signaturE.
702      */
703     public static final int icTagType          = 0;    /* tag type signature */
704 
705     /**
706      * ICC Profile Constant: reserved.
707      */
708     public static final int icTagReserved      = 4;    /* reserved */
709 
710     /**
711      * ICC Profile Constant: curveType count.
712      */
713     public static final int icCurveCount       = 8;    /* curveType count */
714 
715     /**
716      * ICC Profile Constant: curveType data.
717      */
718     public static final int icCurveData        = 12;   /* curveType data */
719 
720     /**
721      * ICC Profile Constant: XYZNumber X.
722      */
723     public static final int icXYZNumberX       = 8;    /* XYZNumber X */
724 
725 
726     /**
727      * Constructs an ICC_Profile object with a given ID.
728      */
729     ICC_Profile(long ID) {
730         this.ID = ID;
731     }
732 
733 
734     /**
735      * Constructs an ICC_Profile object whose loading will be deferred.
736      * The ID will be 0 until the profile is loaded.
737      */
738     ICC_Profile(ProfileDeferralInfo pdi) {
739         this.deferralInfo = pdi;
740         this.profileActivator = new ProfileActivator() {
741             public void activate() throws ProfileDataException {
742                 activateDeferredProfile();
743             }
744         };
745         ProfileDeferralMgr.registerDeferral(this.profileActivator);
746     }
747 
748 
749     /**
750      * Frees the resources associated with an ICC_Profile object.
751      */
752     protected void finalize () {
753         if (ID != 0) {
754             CMSManager.getModule().freeProfile(ID);
755         } else if (profileActivator != null) {
756             ProfileDeferralMgr.unregisterDeferral(profileActivator);
757         }
758     }
759 
760 
761     /**
762      * Constructs an ICC_Profile object corresponding to the data in
763      * a byte array.  Throws an IllegalArgumentException if the data
764      * does not correspond to a valid ICC Profile.
765      * @param data the specified ICC Profile data
766      * @return an <code>ICC_Profile</code> object corresponding to
767      *          the data in the specified <code>data</code> array.
768      */
769     public static ICC_Profile getInstance(byte[] data) {
770     ICC_Profile thisProfile;
771 
772         long theID;
773 
774         if (ProfileDeferralMgr.deferring) {
775             ProfileDeferralMgr.activateProfiles();
776         }
777 
778         try {
779             theID = CMSManager.getModule().loadProfile(data);
780         } catch (CMMException c) {
781             throw new IllegalArgumentException("Invalid ICC Profile Data");
782         }
783 
784         try {
785             if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
786                 (getData (theID, icSigMediaWhitePointTag) != null) &&
787                 (getData (theID, icSigGrayTRCTag) != null)) {
788                 thisProfile = new ICC_ProfileGray (theID);
789             }
790             else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
791                 (getData (theID, icSigMediaWhitePointTag) != null) &&
792                 (getData (theID, icSigRedColorantTag) != null) &&
793                 (getData (theID, icSigGreenColorantTag) != null) &&
794                 (getData (theID, icSigBlueColorantTag) != null) &&
795                 (getData (theID, icSigRedTRCTag) != null) &&
796                 (getData (theID, icSigGreenTRCTag) != null) &&
797                 (getData (theID, icSigBlueTRCTag) != null)) {
798                 thisProfile = new ICC_ProfileRGB (theID);
799             }
800             else {
801                 thisProfile = new ICC_Profile (theID);
802             }
803         } catch (CMMException c) {
804             thisProfile = new ICC_Profile (theID);
805         }
806         return thisProfile;
807     }
808 
809 
810 
811     /**
812      * Constructs an ICC_Profile corresponding to one of the specific color
813      * spaces defined by the ColorSpace class (for example CS_sRGB).
814      * Throws an IllegalArgumentException if cspace is not one of the
815      * defined color spaces.
816      *
817      * @param cspace the type of color space to create a profile for.
818      * The specified type is one of the color
819      * space constants defined in the  <CODE>ColorSpace</CODE> class.
820      *
821      * @return an <code>ICC_Profile</code> object corresponding to
822      *          the specified <code>ColorSpace</code> type.
823      * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
824      * one of the predefined color space types.
825      */
826     public static ICC_Profile getInstance (int cspace) {
827         ICC_Profile thisProfile = null;
828         String fileName;
829 
830         switch (cspace) {
831         case ColorSpace.CS_sRGB:
832             synchronized(ICC_Profile.class) {
833                 if (sRGBprofile == null) {
834                     /*
835                      * Deferral is only used for standard profiles.
836                      * Enabling the appropriate access privileges is handled
837                      * at a lower level.
838                      */
839                     ProfileDeferralInfo pInfo =
840                         new ProfileDeferralInfo("sRGB.pf",
841                                                 ColorSpace.TYPE_RGB, 3,
842                                                 CLASS_DISPLAY);
843                     sRGBprofile = getDeferredInstance(pInfo);
844                 }
845                 thisProfile = sRGBprofile;
846             }
847 
848             break;
849 
850         case ColorSpace.CS_CIEXYZ:
851             synchronized(ICC_Profile.class) {
852                 if (XYZprofile == null) {
853                     ProfileDeferralInfo pInfo =
854                         new ProfileDeferralInfo("CIEXYZ.pf",
855                                                 ColorSpace.TYPE_XYZ, 3,
856                                                 CLASS_DISPLAY);
857                     XYZprofile = getDeferredInstance(pInfo);
858                 }
859                 thisProfile = XYZprofile;
860             }
861 
862             break;
863 
864         case ColorSpace.CS_PYCC:
865             synchronized(ICC_Profile.class) {
866                 if (PYCCprofile == null) {
867                     if (standardProfileExists("PYCC.pf"))
868                     {
869                         ProfileDeferralInfo pInfo =
870                             new ProfileDeferralInfo("PYCC.pf",
871                                                     ColorSpace.TYPE_3CLR, 3,
872                                                     CLASS_DISPLAY);
873                         PYCCprofile = getDeferredInstance(pInfo);
874                     } else {
875                         throw new IllegalArgumentException(
876                                 "Can't load standard profile: PYCC.pf");
877                     }
878                 }
879                 thisProfile = PYCCprofile;
880             }
881 
882             break;
883 
884         case ColorSpace.CS_GRAY:
885             synchronized(ICC_Profile.class) {
886                 if (GRAYprofile == null) {
887                     ProfileDeferralInfo pInfo =
888                         new ProfileDeferralInfo("GRAY.pf",
889                                                 ColorSpace.TYPE_GRAY, 1,
890                                                 CLASS_DISPLAY);
891                     GRAYprofile = getDeferredInstance(pInfo);
892                 }
893                 thisProfile = GRAYprofile;
894             }
895 
896             break;
897 
898         case ColorSpace.CS_LINEAR_RGB:
899             synchronized(ICC_Profile.class) {
900                 if (LINEAR_RGBprofile == null) {
901                     ProfileDeferralInfo pInfo =
902                         new ProfileDeferralInfo("LINEAR_RGB.pf",
903                                                 ColorSpace.TYPE_RGB, 3,
904                                                 CLASS_DISPLAY);
905                     LINEAR_RGBprofile = getDeferredInstance(pInfo);
906                 }
907                 thisProfile = LINEAR_RGBprofile;
908             }
909 
910             break;
911 
912         default:
913             throw new IllegalArgumentException("Unknown color space");
914         }
915 
916         return thisProfile;
917     }
918 
919     /* This asserts system privileges, so is used only for the
920      * standard profiles.
921      */
922     private static ICC_Profile getStandardProfile(final String name) {
923 
924         return (ICC_Profile) AccessController.doPrivileged(
925             new PrivilegedAction() {
926                  public Object run() {
927                      ICC_Profile p = null;
928                      try {
929                          p = getInstance (name);
930                      } catch (IOException ex) {
931                          throw new IllegalArgumentException(
932                                "Can't load standard profile: " + name);
933                      }
934                      return p;
935                  }
936              });
937     }
938 
939     /**
940      * Constructs an ICC_Profile corresponding to the data in a file.
941      * fileName may be an absolute or a relative file specification.
942      * Relative file names are looked for in several places: first, relative
943      * to any directories specified by the java.iccprofile.path property;
944      * second, relative to any directories specified by the java.class.path
945      * property; finally, in a directory used to store profiles always
946      * available, such as the profile for sRGB.  Built-in profiles use .pf as
947      * the file name extension for profiles, e.g. sRGB.pf.
948      * This method throws an IOException if the specified file cannot be
949      * opened or if an I/O error occurs while reading the file.  It throws
950      * an IllegalArgumentException if the file does not contain valid ICC
951      * Profile data.
952      * @param fileName The file that contains the data for the profile.
953      *
954      * @return an <code>ICC_Profile</code> object corresponding to
955      *          the data in the specified file.
956      * @exception IOException If the specified file cannot be opened or
957      * an I/O error occurs while reading the file.
958      *
959      * @exception IllegalArgumentException If the file does not
960      * contain valid ICC Profile data.
961      *
962      * @exception SecurityException If a security manager is installed
963      * and it does not permit read access to the given file.
964      */
965     public static ICC_Profile getInstance(String fileName) throws IOException {
966         ICC_Profile thisProfile;
967         FileInputStream fis = null;
968 
969 
970         File f = getProfileFile(fileName);
971         if (f != null) {
972             fis = new FileInputStream(f);
973         }
974         if (fis == null) {
975             throw new IOException("Cannot open file " + fileName);
976         }
977 
978         thisProfile = getInstance(fis);
979 
980         fis.close();    /* close the file */
981 
982         return thisProfile;
983     }
984 
985 
986     /**
987      * Constructs an ICC_Profile corresponding to the data in an InputStream.
988      * This method throws an IllegalArgumentException if the stream does not
989      * contain valid ICC Profile data.  It throws an IOException if an I/O
990      * error occurs while reading the stream.
991      * @param s The input stream from which to read the profile data.
992      *
993      * @return an <CODE>ICC_Profile</CODE> object corresponding to the
994      *     data in the specified <code>InputStream</code>.
995      *
996      * @exception IOException If an I/O error occurs while reading the stream.
997      *
998      * @exception IllegalArgumentException If the stream does not
999      * contain valid ICC Profile data.
1000      */
1001     public static ICC_Profile getInstance(InputStream s) throws IOException {
1002     byte profileData[];
1003 
1004         if (s instanceof ProfileDeferralInfo) {
1005             /* hack to detect profiles whose loading can be deferred */
1006             return getDeferredInstance((ProfileDeferralInfo) s);
1007         }
1008 
1009         if ((profileData = getProfileDataFromStream(s)) == null) {
1010             throw new IllegalArgumentException("Invalid ICC Profile Data");
1011         }
1012 
1013         return getInstance(profileData);
1014     }
1015 
1016 
1017     static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1018     byte profileData[];
1019     int profileSize;
1020 
1021         byte header[] = new byte[128];
1022         int bytestoread = 128;
1023         int bytesread = 0;
1024         int n;
1025 
1026         while (bytestoread != 0) {
1027             if ((n = s.read(header, bytesread, bytestoread)) < 0) {
1028                 return null;
1029             }
1030             bytesread += n;
1031             bytestoread -= n;
1032         }
1033         if (header[36] != 0x61 || header[37] != 0x63 ||
1034             header[38] != 0x73 || header[39] != 0x70) {
1035             return null;   /* not a valid profile */
1036         }
1037         profileSize = ((header[0] & 0xff) << 24) |
1038                       ((header[1] & 0xff) << 16) |
1039                       ((header[2] & 0xff) <<  8) |
1040                        (header[3] & 0xff);
1041         profileData = new byte[profileSize];
1042         System.arraycopy(header, 0, profileData, 0, 128);
1043         bytestoread = profileSize - 128;
1044         bytesread = 128;
1045         while (bytestoread != 0) {
1046             if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1047                 return null;
1048             }
1049             bytesread += n;
1050             bytestoread -= n;
1051         }
1052 
1053         return profileData;
1054     }
1055 
1056 
1057     /**
1058      * Constructs an ICC_Profile for which the actual loading of the
1059      * profile data from a file and the initialization of the CMM should
1060      * be deferred as long as possible.
1061      * Deferral is only used for standard profiles.
1062      * If deferring is disabled, then getStandardProfile() ensures
1063      * that all of the appropriate access privileges are granted
1064      * when loading this profile.
1065      * If deferring is enabled, then the deferred activation
1066      * code will take care of access privileges.
1067      * @see activateDeferredProfile()
1068      */
1069     static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1070         if (!ProfileDeferralMgr.deferring) {
1071             return getStandardProfile(pdi.filename);
1072         }
1073         if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1074             return new ICC_ProfileRGB(pdi);
1075         } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1076             return new ICC_ProfileGray(pdi);
1077         } else {
1078             return new ICC_Profile(pdi);
1079         }
1080     }
1081 
1082 
1083     void activateDeferredProfile() throws ProfileDataException {
1084         byte profileData[];
1085         FileInputStream fis;
1086         final String fileName = deferralInfo.filename;
1087 
1088         profileActivator = null;
1089         deferralInfo = null;
1090         PrivilegedAction<FileInputStream> pa = new PrivilegedAction<FileInputStream>() {
1091             public FileInputStream run() {
1092                 File f = getStandardProfileFile(fileName);
1093                 if (f != null) {
1094                     try {
1095                         return new FileInputStream(f);
1096                     } catch (FileNotFoundException e) {}
1097                 }
1098                 return null;
1099             }
1100         };
1101         if ((fis = AccessController.doPrivileged(pa)) == null) {
1102             throw new ProfileDataException("Cannot open file " + fileName);
1103         }
1104         try {
1105             profileData = getProfileDataFromStream(fis);
1106             fis.close();    /* close the file */
1107         }
1108         catch (IOException e) {
1109             ProfileDataException pde = new
1110                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1111             pde.initCause(e);
1112             throw pde;
1113         }
1114         if (profileData == null) {
1115             throw new ProfileDataException("Invalid ICC Profile Data" +
1116                 fileName);
1117         }
1118         try {
1119             ID = CMSManager.getModule().loadProfile(profileData);
1120         } catch (CMMException c) {
1121             ProfileDataException pde = new
1122                 ProfileDataException("Invalid ICC Profile Data" + fileName);
1123             pde.initCause(c);
1124             throw pde;
1125         }
1126     }
1127 
1128 
1129     /**
1130      * Returns profile major version.
1131      * @return  The major version of the profile.
1132      */
1133     public int getMajorVersion() {
1134     byte[] theHeader;
1135 
1136         theHeader = getData(icSigHead); /* getData will activate deferred
1137                                            profiles if necessary */
1138 
1139         return (int) theHeader[8];
1140     }
1141 
1142     /**
1143      * Returns profile minor version.
1144      * @return The minor version of the profile.
1145      */
1146     public int getMinorVersion() {
1147     byte[] theHeader;
1148 
1149         theHeader = getData(icSigHead); /* getData will activate deferred
1150                                            profiles if necessary */
1151 
1152         return (int) theHeader[9];
1153     }
1154 
1155     /**
1156      * Returns the profile class.
1157      * @return One of the predefined profile class constants.
1158      */
1159     public int getProfileClass() {
1160     byte[] theHeader;
1161     int theClassSig, theClass;
1162 
1163         if (deferralInfo != null) {
1164             return deferralInfo.profileClass; /* Need to have this info for
1165                                                  ICC_ColorSpace without
1166                                                  causing a deferred profile
1167                                                  to be loaded */
1168         }
1169 
1170         theHeader = getData(icSigHead);
1171 
1172         theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1173 
1174         switch (theClassSig) {
1175         case icSigInputClass:
1176             theClass = CLASS_INPUT;
1177             break;
1178 
1179         case icSigDisplayClass:
1180             theClass = CLASS_DISPLAY;
1181             break;
1182 
1183         case icSigOutputClass:
1184             theClass = CLASS_OUTPUT;
1185             break;
1186 
1187         case icSigLinkClass:
1188             theClass = CLASS_DEVICELINK;
1189             break;
1190 
1191         case icSigColorSpaceClass:
1192             theClass = CLASS_COLORSPACECONVERSION;
1193             break;
1194 
1195         case icSigAbstractClass:
1196             theClass = CLASS_ABSTRACT;
1197             break;
1198 
1199         case icSigNamedColorClass:
1200             theClass = CLASS_NAMEDCOLOR;
1201             break;
1202 
1203         default:
1204             throw new IllegalArgumentException("Unknown profile class");
1205         }
1206 
1207         return theClass;
1208     }
1209 
1210     /**
1211      * Returns the color space type.  Returns one of the color space type
1212      * constants defined by the ColorSpace class.  This is the
1213      * "input" color space of the profile.  The type defines the
1214      * number of components of the color space and the interpretation,
1215      * e.g. TYPE_RGB identifies a color space with three components - red,
1216      * green, and blue.  It does not define the particular color
1217      * characteristics of the space, e.g. the chromaticities of the
1218      * primaries.
1219      * @return One of the color space type constants defined in the
1220      * <CODE>ColorSpace</CODE> class.
1221      */
1222     public int getColorSpaceType() {
1223         if (deferralInfo != null) {
1224             return deferralInfo.colorSpaceType; /* Need to have this info for
1225                                                    ICC_ColorSpace without
1226                                                    causing a deferred profile
1227                                                    to be loaded */
1228         }
1229         return    getColorSpaceType(ID);
1230     }
1231 
1232     static int getColorSpaceType(long profileID) {
1233     byte[] theHeader;
1234     int theColorSpaceSig, theColorSpace;
1235 
1236         theHeader = getData(profileID, icSigHead);
1237         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1238         theColorSpace = iccCStoJCS (theColorSpaceSig);
1239         return theColorSpace;
1240     }
1241 
1242     /**
1243      * Returns the color space type of the Profile Connection Space (PCS).
1244      * Returns one of the color space type constants defined by the
1245      * ColorSpace class.  This is the "output" color space of the
1246      * profile.  For an input, display, or output profile useful
1247      * for tagging colors or images, this will be either TYPE_XYZ or
1248      * TYPE_Lab and should be interpreted as the corresponding specific
1249      * color space defined in the ICC specification.  For a device
1250      * link profile, this could be any of the color space type constants.
1251      * @return One of the color space type constants defined in the
1252      * <CODE>ColorSpace</CODE> class.
1253      */
1254     public int getPCSType() {
1255         if (ProfileDeferralMgr.deferring) {
1256             ProfileDeferralMgr.activateProfiles();
1257         }
1258         return getPCSType(ID);
1259     }
1260 
1261 
1262     static int getPCSType(long profileID) {
1263     byte[] theHeader;
1264     int thePCSSig, thePCS;
1265 
1266         theHeader = getData(profileID, icSigHead);
1267         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1268         thePCS = iccCStoJCS(thePCSSig);
1269         return thePCS;
1270     }
1271 
1272 
1273     /**
1274      * Write this ICC_Profile to a file.
1275      *
1276      * @param fileName The file to write the profile data to.
1277      *
1278      * @exception IOException If the file cannot be opened for writing
1279      * or an I/O error occurs while writing to the file.
1280      */
1281     public void write(String fileName) throws IOException {
1282     FileOutputStream outputFile;
1283     byte profileData[];
1284 
1285         profileData = getData(); /* this will activate deferred
1286                                     profiles if necessary */
1287         outputFile = new FileOutputStream(fileName);
1288         outputFile.write(profileData);
1289         outputFile.close ();
1290     }
1291 
1292 
1293     /**
1294      * Write this ICC_Profile to an OutputStream.
1295      *
1296      * @param s The stream to write the profile data to.
1297      *
1298      * @exception IOException If an I/O error occurs while writing to the
1299      * stream.
1300      */
1301     public void write(OutputStream s) throws IOException {
1302     byte profileData[];
1303 
1304         profileData = getData(); /* this will activate deferred
1305                                     profiles if necessary */
1306         s.write(profileData);
1307     }
1308 
1309 
1310     /**
1311      * Returns a byte array corresponding to the data of this ICC_Profile.
1312      * @return A byte array that contains the profile data.
1313      * @see #setData(int, byte[])
1314      */
1315     public byte[] getData() {
1316     int profileSize;
1317     byte[] profileData;
1318 
1319         if (ProfileDeferralMgr.deferring) {
1320             ProfileDeferralMgr.activateProfiles();
1321         }
1322 
1323         PCMM mdl = CMSManager.getModule();
1324 
1325         /* get the number of bytes needed for this profile */
1326         profileSize = mdl.getProfileSize(ID);
1327 
1328         profileData = new byte [profileSize];
1329 
1330         /* get the data for the profile */
1331         mdl.getProfileData(ID, profileData);
1332 
1333         return profileData;
1334     }
1335 
1336 
1337     /**
1338      * Returns a particular tagged data element from the profile as
1339      * a byte array.  Elements are identified by signatures
1340      * as defined in the ICC specification.  The signature
1341      * icSigHead can be used to get the header.  This method is useful
1342      * for advanced applets or applications which need to access
1343      * profile data directly.
1344      *
1345      * @param tagSignature The ICC tag signature for the data element you
1346      * want to get.
1347      *
1348      * @return A byte array that contains the tagged data element. Returns
1349      * <code>null</code> if the specified tag doesn't exist.
1350      * @see #setData(int, byte[])
1351      */
1352     public byte[] getData(int tagSignature) {
1353 
1354         if (ProfileDeferralMgr.deferring) {
1355             ProfileDeferralMgr.activateProfiles();
1356         }
1357 
1358         return getData(ID, tagSignature);
1359     }
1360 
1361 
1362     static byte[] getData(long profileID, int tagSignature) {
1363     int tagSize;
1364     byte[] tagData;
1365 
1366         try {
1367             PCMM mdl = CMSManager.getModule();
1368 
1369             /* get the number of bytes needed for this tag */
1370             tagSize = mdl.getTagSize(profileID, tagSignature);
1371 
1372             tagData = new byte[tagSize]; /* get an array for the tag */
1373 
1374             /* get the tag's data */
1375             mdl.getTagData(profileID, tagSignature, tagData);
1376         } catch(CMMException c) {
1377             tagData = null;
1378         }
1379 
1380         return tagData;
1381     }
1382 
1383     /**
1384      * Sets a particular tagged data element in the profile from
1385      * a byte array. The array should contain data in a format, corresponded
1386      * to the {@code tagSignature} as defined in the ICC specification, section 10.
1387      * This method is useful for advanced applets or applications which need to
1388      * access profile data directly.
1389      *
1390      * @param tagSignature The ICC tag signature for the data element
1391      * you want to set.
1392      * @param tagData the data to set for the specified tag signature
1393      * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1394      *         as defined in the ICC specification.
1395      * @throws IllegalArgumentException if a content of the {@code tagData}
1396      *         array can not be interpreted as valid tag data, corresponding
1397      *         to the {@code tagSignature}.
1398      * @see #getData
1399      */
1400     public void setData(int tagSignature, byte[] tagData) {
1401 
1402         if (ProfileDeferralMgr.deferring) {
1403             ProfileDeferralMgr.activateProfiles();
1404         }
1405 
1406         CMSManager.getModule().setTagData(ID, tagSignature, tagData);
1407     }
1408 
1409     /**
1410      * Sets the rendering intent of the profile.
1411      * This is used to select the proper transform from a profile that
1412      * has multiple transforms.
1413      */
1414     void setRenderingIntent(int renderingIntent) {
1415         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1416                                                  profiles if necessary */
1417         intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1418                                                  /* set the rendering intent */
1419         setData (icSigHead, theHeader);
1420     }
1421 
1422 
1423     /**
1424      * Returns the rendering intent of the profile.
1425      * This is used to select the proper transform from a profile that
1426      * has multiple transforms.  It is typically set in a source profile
1427      * to select a transform from an output profile.
1428      */
1429     int getRenderingIntent() {
1430         byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1431                                                  profiles if necessary */
1432 
1433         int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1434                                                  /* set the rendering intent */
1435         return renderingIntent;
1436     }
1437 
1438 
1439     /**
1440      * Returns the number of color components in the "input" color
1441      * space of this profile.  For example if the color space type
1442      * of this profile is TYPE_RGB, then this method will return 3.
1443      *
1444      * @return The number of color components in the profile's input
1445      * color space.
1446      *
1447      * @throws ProfileDataException if color space is in the profile
1448      *         is invalid
1449      */
1450     public int getNumComponents() {
1451     byte[]    theHeader;
1452     int    theColorSpaceSig, theNumComponents;
1453 
1454         if (deferralInfo != null) {
1455             return deferralInfo.numComponents; /* Need to have this info for
1456                                                   ICC_ColorSpace without
1457                                                   causing a deferred profile
1458                                                   to be loaded */
1459         }
1460         theHeader = getData(icSigHead);
1461 
1462         theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1463 
1464         switch (theColorSpaceSig) {
1465         case icSigGrayData:
1466             theNumComponents = 1;
1467             break;
1468 
1469         case icSigSpace2CLR:
1470             theNumComponents = 2;
1471             break;
1472 
1473         case icSigXYZData:
1474         case icSigLabData:
1475         case icSigLuvData:
1476         case icSigYCbCrData:
1477         case icSigYxyData:
1478         case icSigRgbData:
1479         case icSigHsvData:
1480         case icSigHlsData:
1481         case icSigCmyData:
1482         case icSigSpace3CLR:
1483             theNumComponents = 3;
1484             break;
1485 
1486         case icSigCmykData:
1487         case icSigSpace4CLR:
1488             theNumComponents = 4;
1489             break;
1490 
1491         case icSigSpace5CLR:
1492             theNumComponents = 5;
1493             break;
1494 
1495         case icSigSpace6CLR:
1496             theNumComponents = 6;
1497             break;
1498 
1499         case icSigSpace7CLR:
1500             theNumComponents = 7;
1501             break;
1502 
1503         case icSigSpace8CLR:
1504             theNumComponents = 8;
1505             break;
1506 
1507         case icSigSpace9CLR:
1508             theNumComponents = 9;
1509             break;
1510 
1511         case icSigSpaceACLR:
1512             theNumComponents = 10;
1513             break;
1514 
1515         case icSigSpaceBCLR:
1516             theNumComponents = 11;
1517             break;
1518 
1519         case icSigSpaceCCLR:
1520             theNumComponents = 12;
1521             break;
1522 
1523         case icSigSpaceDCLR:
1524             theNumComponents = 13;
1525             break;
1526 
1527         case icSigSpaceECLR:
1528             theNumComponents = 14;
1529             break;
1530 
1531         case icSigSpaceFCLR:
1532             theNumComponents = 15;
1533             break;
1534 
1535         default:
1536             throw new ProfileDataException ("invalid ICC color space");
1537         }
1538 
1539         return theNumComponents;
1540     }
1541 
1542 
1543     /**
1544      * Returns a float array of length 3 containing the X, Y, and Z
1545      * components of the mediaWhitePointTag in the ICC profile.
1546      */
1547     float[] getMediaWhitePoint() {
1548         return getXYZTag(icSigMediaWhitePointTag);
1549                                            /* get the media white point tag */
1550     }
1551 
1552 
1553     /**
1554      * Returns a float array of length 3 containing the X, Y, and Z
1555      * components encoded in an XYZType tag.
1556      */
1557     float[] getXYZTag(int theTagSignature) {
1558     byte[] theData;
1559     float[] theXYZNumber;
1560     int i1, i2, theS15Fixed16;
1561 
1562         theData = getData(theTagSignature); /* get the tag data */
1563                                             /* getData will activate deferred
1564                                                profiles if necessary */
1565 
1566         theXYZNumber = new float [3];        /* array to return */
1567 
1568         /* convert s15Fixed16Number to float */
1569         for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1570             theS15Fixed16 = intFromBigEndian(theData, i2);
1571             theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1572         }
1573         return theXYZNumber;
1574     }
1575 
1576 
1577     /**
1578      * Returns a gamma value representing a tone reproduction
1579      * curve (TRC).  If the profile represents the TRC as a table rather
1580      * than a single gamma value, then an exception is thrown.  In this
1581      * case the actual table can be obtained via getTRC().
1582      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1583      * icSigGreenTRCTag, or icSigBlueTRCTag.
1584      * @return the gamma value as a float.
1585      * @exception ProfileDataException if the profile does not specify
1586      *            the TRC as a single gamma value.
1587      */
1588     float getGamma(int theTagSignature) {
1589     byte[] theTRCData;
1590     float theGamma;
1591     int theU8Fixed8;
1592 
1593         theTRCData = getData(theTagSignature); /* get the TRC */
1594                                                /* getData will activate deferred
1595                                                   profiles if necessary */
1596 
1597         if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1598             throw new ProfileDataException ("TRC is not a gamma");
1599         }
1600 
1601         /* convert u8Fixed8 to float */
1602         theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1603 
1604         theGamma = ((float) theU8Fixed8) / 256.0f;
1605 
1606         return theGamma;
1607     }
1608 
1609 
1610     /**
1611      * Returns the TRC as an array of shorts.  If the profile has
1612      * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1613      * value, this method throws an exception, and the getGamma() method
1614      * should be used to get the gamma value.  Otherwise the short array
1615      * returned here represents a lookup table where the input Gray value
1616      * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
1617      * to array index 0 and value 1.0 maps to array index length-1.
1618      * Interpolation may be used to generate output values for
1619      * input values which do not map exactly to an index in the
1620      * array.  Output values also map linearly to the range [0.0, 1.0].
1621      * Value 0.0 is represented by an array value of 0x0000 and
1622      * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1623      * short values, although they are returned in a short array.
1624      * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1625      * icSigGreenTRCTag, or icSigBlueTRCTag.
1626      * @return a short array representing the TRC.
1627      * @exception ProfileDataException if the profile does not specify
1628      *            the TRC as a table.
1629      */
1630     short[] getTRC(int theTagSignature) {
1631     byte[] theTRCData;
1632     short[] theTRC;
1633     int i1, i2, nElements, theU8Fixed8;
1634 
1635         theTRCData = getData(theTagSignature); /* get the TRC */
1636                                                /* getData will activate deferred
1637                                                   profiles if necessary */
1638 
1639         nElements = intFromBigEndian(theTRCData, icCurveCount);
1640 
1641         if (nElements == 1) {
1642             throw new ProfileDataException("TRC is not a table");
1643         }
1644 
1645         /* make the short array */
1646         theTRC = new short [nElements];
1647 
1648         for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1649             theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1650         }
1651 
1652         return theTRC;
1653     }
1654 
1655 
1656     /* convert an ICC color space signature into a Java color space type */
1657     static int iccCStoJCS(int theColorSpaceSig) {
1658     int theColorSpace;
1659 
1660         switch (theColorSpaceSig) {
1661         case icSigXYZData:
1662             theColorSpace = ColorSpace.TYPE_XYZ;
1663             break;
1664 
1665         case icSigLabData:
1666             theColorSpace = ColorSpace.TYPE_Lab;
1667             break;
1668 
1669         case icSigLuvData:
1670             theColorSpace = ColorSpace.TYPE_Luv;
1671             break;
1672 
1673         case icSigYCbCrData:
1674             theColorSpace = ColorSpace.TYPE_YCbCr;
1675             break;
1676 
1677         case icSigYxyData:
1678             theColorSpace = ColorSpace.TYPE_Yxy;
1679             break;
1680 
1681         case icSigRgbData:
1682             theColorSpace = ColorSpace.TYPE_RGB;
1683             break;
1684 
1685         case icSigGrayData:
1686             theColorSpace = ColorSpace.TYPE_GRAY;
1687             break;
1688 
1689         case icSigHsvData:
1690             theColorSpace = ColorSpace.TYPE_HSV;
1691             break;
1692 
1693         case icSigHlsData:
1694             theColorSpace = ColorSpace.TYPE_HLS;
1695             break;
1696 
1697         case icSigCmykData:
1698             theColorSpace = ColorSpace.TYPE_CMYK;
1699             break;
1700 
1701         case icSigCmyData:
1702             theColorSpace = ColorSpace.TYPE_CMY;
1703             break;
1704 
1705         case icSigSpace2CLR:
1706             theColorSpace = ColorSpace.TYPE_2CLR;
1707             break;
1708 
1709         case icSigSpace3CLR:
1710             theColorSpace = ColorSpace.TYPE_3CLR;
1711             break;
1712 
1713         case icSigSpace4CLR:
1714             theColorSpace = ColorSpace.TYPE_4CLR;
1715             break;
1716 
1717         case icSigSpace5CLR:
1718             theColorSpace = ColorSpace.TYPE_5CLR;
1719             break;
1720 
1721         case icSigSpace6CLR:
1722             theColorSpace = ColorSpace.TYPE_6CLR;
1723             break;
1724 
1725         case icSigSpace7CLR:
1726             theColorSpace = ColorSpace.TYPE_7CLR;
1727             break;
1728 
1729         case icSigSpace8CLR:
1730             theColorSpace = ColorSpace.TYPE_8CLR;
1731             break;
1732 
1733         case icSigSpace9CLR:
1734             theColorSpace = ColorSpace.TYPE_9CLR;
1735             break;
1736 
1737         case icSigSpaceACLR:
1738             theColorSpace = ColorSpace.TYPE_ACLR;
1739             break;
1740 
1741         case icSigSpaceBCLR:
1742             theColorSpace = ColorSpace.TYPE_BCLR;
1743             break;
1744 
1745         case icSigSpaceCCLR:
1746             theColorSpace = ColorSpace.TYPE_CCLR;
1747             break;
1748 
1749         case icSigSpaceDCLR:
1750             theColorSpace = ColorSpace.TYPE_DCLR;
1751             break;
1752 
1753         case icSigSpaceECLR:
1754             theColorSpace = ColorSpace.TYPE_ECLR;
1755             break;
1756 
1757         case icSigSpaceFCLR:
1758             theColorSpace = ColorSpace.TYPE_FCLR;
1759             break;
1760 
1761         default:
1762             throw new IllegalArgumentException ("Unknown color space");
1763         }
1764 
1765         return theColorSpace;
1766     }
1767 
1768 
1769     static int intFromBigEndian(byte[] array, int index) {
1770         return (((array[index]   & 0xff) << 24) |
1771                 ((array[index+1] & 0xff) << 16) |
1772                 ((array[index+2] & 0xff) <<  8) |
1773                  (array[index+3] & 0xff));
1774     }
1775 
1776 
1777     static void intToBigEndian(int value, byte[] array, int index) {
1778             array[index]   = (byte) (value >> 24);
1779             array[index+1] = (byte) (value >> 16);
1780             array[index+2] = (byte) (value >>  8);
1781             array[index+3] = (byte) (value);
1782     }
1783 
1784 
1785     static short shortFromBigEndian(byte[] array, int index) {
1786         return (short) (((array[index]   & 0xff) << 8) |
1787                          (array[index+1] & 0xff));
1788     }
1789 
1790 
1791     static void shortToBigEndian(short value, byte[] array, int index) {
1792             array[index]   = (byte) (value >> 8);
1793             array[index+1] = (byte) (value);
1794     }
1795 
1796 
1797     /*
1798      * fileName may be an absolute or a relative file specification.
1799      * Relative file names are looked for in several places: first, relative
1800      * to any directories specified by the java.iccprofile.path property;
1801      * second, relative to any directories specified by the java.class.path
1802      * property; finally, in a directory used to store profiles always
1803      * available, such as a profile for sRGB.  Built-in profiles use .pf as
1804      * the file name extension for profiles, e.g. sRGB.pf.
1805      */
1806     private static File getProfileFile(String fileName) {
1807         String path, dir, fullPath;
1808 
1809         File f = new File(fileName); /* try absolute file name */
1810         if (f.isAbsolute()) {
1811             /* Rest of code has little sense for an absolute pathname,
1812                so return here. */
1813             return f.isFile() ? f : null;
1814         }
1815         if ((!f.isFile()) &&
1816                 ((path = System.getProperty("java.iccprofile.path")) != null)){
1817                                     /* try relative to java.iccprofile.path */
1818                 StringTokenizer st =
1819                     new StringTokenizer(path, File.pathSeparator);
1820                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1821                     dir = st.nextToken();
1822                         fullPath = dir + File.separatorChar + fileName;
1823                     f = new File(fullPath);
1824                     if (!isChildOf(f, dir)) {
1825                         f = null;
1826                     }
1827                 }
1828             }
1829 
1830         if (((f == null) || (!f.isFile())) &&
1831                 ((path = System.getProperty("java.class.path")) != null)) {
1832                                     /* try relative to java.class.path */
1833                 StringTokenizer st =
1834                     new StringTokenizer(path, File.pathSeparator);
1835                 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1836                     dir = st.nextToken();
1837                         fullPath = dir + File.separatorChar + fileName;
1838                     f = new File(fullPath);
1839                 }
1840             }
1841 
1842         if ((f == null) || (!f.isFile())) {
1843             /* try the directory of built-in profiles */
1844             f = getStandardProfileFile(fileName);
1845         }
1846         if (f != null && f.isFile()) {
1847             return f;
1848         }
1849         return null;
1850     }
1851 
1852     /**
1853      * Returns a file object corresponding to a built-in profile
1854      * specified by fileName.
1855      * If there is no built-in profile with such name, then the method
1856      * returns null.
1857      */
1858     private static File getStandardProfileFile(String fileName) {
1859         String dir = System.getProperty("java.home") +
1860             File.separatorChar + "lib" + File.separatorChar + "cmm";
1861         String fullPath = dir + File.separatorChar + fileName;
1862         File f = new File(fullPath);
1863         return (f.isFile() && isChildOf(f, dir)) ? f : null;
1864     }
1865 
1866     /**
1867      * Checks whether given file resides inside give directory.
1868      */
1869     private static boolean isChildOf(File f, String dirName) {
1870         try {
1871             File dir = new File(dirName);
1872             String canonicalDirName = dir.getCanonicalPath();
1873             if (!canonicalDirName.endsWith(File.separator)) {
1874                 canonicalDirName += File.separator;
1875             }
1876             String canonicalFileName = f.getCanonicalPath();
1877             return canonicalFileName.startsWith(canonicalDirName);
1878         } catch (IOException e) {
1879             /* we do not expect the IOException here, because invocation
1880              * of this function is always preceeded by isFile() call.
1881              */
1882             return false;
1883         }
1884     }
1885 
1886     /**
1887      * Checks whether built-in profile specified by fileName exists.
1888      */
1889     private static boolean standardProfileExists(final String fileName) {
1890         return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1891                 public Boolean run() {
1892                     return getStandardProfileFile(fileName) != null;
1893                 }
1894             });
1895     }
1896 
1897 
1898     /*
1899      * Serialization support.
1900      *
1901      * Directly deserialized profiles are useless since they are not
1902      * registered with CMM.  We don't allow constructor to be called
1903      * directly and instead have clients to call one of getInstance
1904      * factory methods that will register the profile with CMM.  For
1905      * deserialization we implement readResolve method that will
1906      * resolve the bogus deserialized profile object with one obtained
1907      * with getInstance as well.
1908      *
1909      * There're two primary factory methods for construction of ICC
1910      * profiles: getInstance(int cspace) and getInstance(byte[] data).
1911      * This implementation of ICC_Profile uses the former to return a
1912      * cached singleton profile object, other implementations will
1913      * likely use this technique too.  To preserve the singleton
1914      * pattern across serialization we serialize cached singleton
1915      * profiles in such a way that deserializing VM could call
1916      * getInstance(int cspace) method that will resolve deserialized
1917      * object into the corresponding singleton as well.
1918      *
1919      * Since the singletons are private to ICC_Profile the readResolve
1920      * method have to be `protected' instead of `private' so that
1921      * singletons that are instances of subclasses of ICC_Profile
1922      * could be correctly deserialized.
1923      */
1924 
1925 
1926     /**
1927      * Version of the format of additional serialized data in the
1928      * stream.  Version&nbsp;<code>1</code> corresponds to Java&nbsp;2
1929      * Platform,&nbsp;v1.3.
1930      * @since 1.3
1931      * @serial
1932      */
1933     private int iccProfileSerializedDataVersion = 1;
1934 
1935 
1936     /**
1937      * Writes default serializable fields to the stream.  Writes a
1938      * string and an array of bytes to the stream as additional data.
1939      *
1940      * @param s stream used for serialization.
1941      * @throws IOException
1942      *     thrown by <code>ObjectInputStream</code>.
1943      * @serialData
1944      *     The <code>String</code> is the name of one of
1945      *     <code>CS_<var>*</var></code> constants defined in the
1946      *     {@link ColorSpace} class if the profile object is a profile
1947      *     for a predefined color space (for example
1948      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
1949      *     otherwise.
1950      *     <p>
1951      *     The <code>byte[]</code> array is the profile data for the
1952      *     profile.  For predefined color spaces <code>null</code> is
1953      *     written instead of the profile data.  If in the future
1954      *     versions of Java API new predefined color spaces will be
1955      *     added, future versions of this class may choose to write
1956      *     for new predefined color spaces not only the color space
1957      *     name, but the profile data as well so that older versions
1958      *     could still deserialize the object.
1959      */
1960     private void writeObject(ObjectOutputStream s)
1961       throws IOException
1962     {
1963         s.defaultWriteObject();
1964 
1965         String csName = null;
1966         if (this == sRGBprofile) {
1967             csName = "CS_sRGB";
1968         } else if (this == XYZprofile) {
1969             csName = "CS_CIEXYZ";
1970         } else if (this == PYCCprofile) {
1971             csName = "CS_PYCC";
1972         } else if (this == GRAYprofile) {
1973             csName = "CS_GRAY";
1974         } else if (this == LINEAR_RGBprofile) {
1975             csName = "CS_LINEAR_RGB";
1976         }
1977 
1978         // Future versions may choose to write profile data for new
1979         // predefined color spaces as well, if any will be introduced,
1980         // so that old versions that don't recognize the new CS name
1981         // may fall back to constructing profile from the data.
1982         byte[] data = null;
1983         if (csName == null) {
1984             // getData will activate deferred profile if necessary
1985             data = getData();
1986         }
1987 
1988         s.writeObject(csName);
1989         s.writeObject(data);
1990     }
1991 
1992     // Temporary storage used by readObject to store resolved profile
1993     // (obtained with getInstance) for readResolve to return.
1994     private transient ICC_Profile resolvedDeserializedProfile;
1995 
1996     /**
1997      * Reads default serializable fields from the stream.  Reads from
1998      * the stream a string and an array of bytes as additional data.
1999      *
2000      * @param s stream used for deserialization.
2001      * @throws IOException
2002      *     thrown by <code>ObjectInputStream</code>.
2003      * @throws ClassNotFoundException
2004      *     thrown by <code>ObjectInputStream</code>.
2005      * @serialData
2006      *     The <code>String</code> is the name of one of
2007      *     <code>CS_<var>*</var></code> constants defined in the
2008      *     {@link ColorSpace} class if the profile object is a profile
2009      *     for a predefined color space (for example
2010      *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
2011      *     otherwise.
2012      *     <p>
2013      *     The <code>byte[]</code> array is the profile data for the
2014      *     profile.  It will usually be <code>null</code> for the
2015      *     predefined profiles.
2016      *     <p>
2017      *     If the string is recognized as a constant name for
2018      *     predefined color space the object will be resolved into
2019      *     profile obtained with
2020      *     <code>getInstance(int&nbsp;cspace)</code> and the profile
2021      *     data are ignored.  Otherwise the object will be resolved
2022      *     into profile obtained with
2023      *     <code>getInstance(byte[]&nbsp;data)</code>.
2024      * @see #readResolve()
2025      * @see #getInstance(int)
2026      * @see #getInstance(byte[])
2027      */
2028     private void readObject(ObjectInputStream s)
2029       throws IOException, ClassNotFoundException
2030     {
2031         s.defaultReadObject();
2032 
2033         String csName = (String)s.readObject();
2034         byte[] data = (byte[])s.readObject();
2035 
2036         int cspace = 0;         // ColorSpace.CS_* constant if known
2037         boolean isKnownPredefinedCS = false;
2038         if (csName != null) {
2039             isKnownPredefinedCS = true;
2040             if (csName.equals("CS_sRGB")) {
2041                 cspace = ColorSpace.CS_sRGB;
2042             } else if (csName.equals("CS_CIEXYZ")) {
2043                 cspace = ColorSpace.CS_CIEXYZ;
2044             } else if (csName.equals("CS_PYCC")) {
2045                 cspace = ColorSpace.CS_PYCC;
2046             } else if (csName.equals("CS_GRAY")) {
2047                 cspace = ColorSpace.CS_GRAY;
2048             } else if (csName.equals("CS_LINEAR_RGB")) {
2049                 cspace = ColorSpace.CS_LINEAR_RGB;
2050             } else {
2051                 isKnownPredefinedCS = false;
2052             }
2053         }
2054 
2055         if (isKnownPredefinedCS) {
2056             resolvedDeserializedProfile = getInstance(cspace);
2057         } else {
2058             resolvedDeserializedProfile = getInstance(data);
2059         }
2060     }
2061 
2062     /**
2063      * Resolves instances being deserialized into instances registered
2064      * with CMM.
2065      * @return ICC_Profile object for profile registered with CMM.
2066      * @throws ObjectStreamException
2067      *     never thrown, but mandated by the serialization spec.
2068      * @since 1.3
2069      */
2070     protected Object readResolve() throws ObjectStreamException {
2071         return resolvedDeserializedProfile;
2072     }
2073 }